home *** CD-ROM | disk | FTP | other *** search
/ Aminet 40 / Aminet 40 (2000)(Schatztruhe)[!][Dec 2000].iso / Aminet / dev / src / xad_ZAP.lha / ZAP.c < prev   
C/C++ Source or Header  |  2000-08-06  |  8KB  |  274 lines

  1. /* This XAD client is (C) 2000 Stuart Caie <kyzer@4u.net>
  2.  *
  3.  * This program is free software; you can redistribute it and/or modify
  4.  * it under the terms of the GNU General Public License as published by
  5.  * the Free Software Foundation; either version 2 of the License, or
  6.  * (at your option) any later version.
  7.  *
  8.  * This program is distributed in the hope that it will be useful,
  9.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11.  * GNU General Public License for more details.
  12.  *
  13.  * You should have received a copy of the GNU General Public License
  14.  * along with this program; if not, write to the Free Software
  15.  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16.  */
  17.  
  18. /* ZAP is a lesser-known Amiga disk archiver. This client is only tested
  19.  * with ZAP v1.41. It uses byte-based run-length encoding and LZ78
  20.  * compression, which is redundant because the LZ compressor handles
  21.  * repeated byte runs really well. The archiver only supports normal
  22.  * Amiga DOS disks (80*2*11*512 = 901120 bytes), and it compresses them
  23.  * in 10 blocks of 8 cylinders. It also supports using the AmigaDOS
  24.  * disk bitmap, but just by clearing those sectors before compression,
  25.  * not some special format. Finally, it supports attaching a textfile/
  26.  * banner to the archive, shown on extraction. ZAP is (C) 1990 GREMLIN of
  27.  * MAYHEM.
  28.  *
  29.  * $VER: ZAP.c 1.2 (05.08.2000)";
  30.  
  31.  */
  32.  
  33. #include <proto/xadmaster.h>
  34. #include <libraries/xadmaster.h>
  35. #include <exec/memory.h>
  36. #include <string.h>
  37.  
  38. #include "ConvertE.c"
  39. #include "SDI_compiler.h"
  40.  
  41. #ifndef XADMASTERFILE
  42. #define ZAP_Client        FirstClient
  43. #define NEXTCLIENT        0
  44. UBYTE version[] = "$VER: ZAP 1.1 (05.08.2000)";
  45. #endif
  46. #define ZAP_VERSION     1
  47. #define ZAP_REVISION    1
  48.  
  49.  
  50. #define XADBASE REG(a6, struct xadMasterBase *xadMasterBase)
  51.  
  52. /* work-doing macros */
  53. #define SKIP(offset) if ((err = xadHookAccess(XADAC_INPUTSEEK, \
  54.   (ULONG)(offset), NULL, ai))) goto exit_handler
  55. #define SEEK(offset) SKIP((offset) - ai->xai_InPos)
  56. #define READ(buffer,length) if ((err = xadHookAccess(XADAC_READ, \
  57.   (ULONG)(length), (APTR)(buffer), ai))) goto exit_handler
  58. #define WRITE(buffer,length) if ((err = xadHookAccess(XADAC_WRITE, \
  59.   (ULONG)(length), (APTR)(buffer), ai))) goto exit_handler
  60.  
  61. #define ERROR(error) do { err = XADERR_##error; goto exit_handler; } while(0)
  62. #define ALLOC(t,v,l) \
  63.   if (!((v) = (t) xadAllocVec((l),MEMF_CLEAR))) ERROR(NOMEMORY)
  64. #define ALLOCOBJ(t,v,kind,tags) \
  65.   if (!((v) = (t) xadAllocObjectA((kind),(tags)))) ERROR(NOMEMORY)
  66. #define FREE(obj) xadFreeObjectA((APTR)(obj),NULL)
  67.  
  68. #define READLONG(var) do { READ(&buffer,4); (var)=EndGetM32(buffer);} while(0)
  69.  
  70.  
  71. /* main ZAP LZ78 decruncher */
  72. struct ZAPdecr {
  73.   /* bitbuffer, checksum, input pointer, input beginning, bits left, error */
  74.   ULONG bb, sum; UBYTE *i, *in, bl, err;
  75. };
  76. ULONG ZAP_getlong(struct ZAPdecr *zd) {
  77.   UBYTE *in; if ((in=(zd->i -= 4)) < zd->in) {zd->err=XADERR_INPUT; return 0;}
  78.   return EndGetM32(in);
  79. }
  80. ULONG ZAP_getbits(struct ZAPdecr *zd, int n) {
  81.   int x=0; ULONG bb = zd->bb;
  82.   while (n--) {
  83.     if (!zd->bl--) { zd->sum ^= (bb = ZAP_getlong(zd)); zd->bl = 31; }
  84.     x = (x<<1) | (bb&1); bb >>= 1;
  85.   }
  86.   zd->bb = bb;
  87.   return x;
  88. }
  89.  
  90. #define BITS(n) (ZAP_getbits(&zd, (n)))
  91. #define BIT     (ZAP_getbits(&zd, 1))
  92. #define PUT(x)  if(--o < out) return XADERR_OUTPUT; else *o=(UBYTE)(x)
  93.  
  94. LONG ZAP_decrunch(UBYTE *in, UBYTE *out, ULONG inlen) {
  95.   struct ZAPdecr zd;
  96.   UBYTE *match, *o;
  97.   int x, y;
  98.  
  99.   /* initialise state */
  100.   zd.bb  = 0;
  101.   zd.bl  = 0;
  102.   zd.err = XADERR_OK;
  103.   zd.in  = in;
  104.   zd.i   = in + inlen;
  105.   o      = out + ZAP_getlong(&zd);
  106.   zd.sum = ZAP_getlong(&zd);
  107.  
  108.   /* throw away bits up to first set bit */
  109.   while (!BIT) if (zd.err) break;
  110.  
  111.   while (o > out) {
  112.     if ((x=BITS(2)) == 3) x = BIT ? (BIT ? -1 : (BITS(8)+19)) : (BITS(4)+3);
  113.     if (x >= 0) do { PUT(BITS(8)); } while (x-- > 0);
  114.     if (o <= out) break;
  115.  
  116.     if ((x = BITS(2)) == 3) {
  117.       x = BIT ? (BIT ? -1 : (BITS(8)+20)) : (BITS(4)+4);
  118.       if (x >= 0) y = BIT ? (BITS(13)+258) : (BITS(8)+2);
  119.     }
  120.     else {
  121.       if (x) { x++; y = BIT ? (BITS(13)+258) : (BITS(8)+2); }
  122.       else   { x=1; y = BITS(8)+2; }
  123.     }
  124.     match = o + y; if (x >= 0) do { PUT(*--match); } while (x-- > 0);
  125.   }
  126.  
  127.   /* checksum should be 0 on exit */
  128.   if (!zd.err && zd.sum) zd.err = XADERR_CHECKSUM;
  129.   return (LONG) zd.err;
  130. }
  131.  
  132.  
  133. /* RLE decoder for compressed blocks */
  134. void ZAP_rledecode(UBYTE *in, UBYTE *out) {
  135.   UBYTE *i = in+9, *o = out, *end=out + EndGetM32(in+4);
  136.   int code=in[8], x, y;
  137.  
  138.   while (o < end) {
  139.     if ((x = *i++) == code) {
  140.       if ((x = *i++)) { y=*i++; x+=3; while (x--) *o++=y; } else *o++ = code;
  141.     }
  142.     else *o++ = x;
  143.   }
  144. }
  145.  
  146.  
  147. ASM(BOOL) ZAP_RecogData(REG(d0, ULONG size), REG(a0, UBYTE *data), XADBASE) {
  148.   return (BOOL) (strncmp("ZAP V1.41", data+4, 9) == 0);
  149. }
  150.  
  151.  
  152. ASM(LONG) ZAP_GetInfo(REG(a0, struct xadArchiveInfo *ai), XADBASE) {
  153.   UBYTE buffer[4], *textin = NULL;
  154.   struct xadDiskInfo *xdi = NULL;
  155.   struct xadTextInfo *ti;
  156.   LONG err = XADERR_OK;
  157.   ULONG tfsize;
  158.  
  159.   ALLOCOBJ(struct xadDiskInfo *, xdi, XADOBJ_DISKINFO, NULL);
  160.   ai->xai_DiskInfo = xdi;
  161.   xdi->xdi_EntryNumber  = 1;
  162.   xdi->xdi_SectorSize   = 512;
  163.   xdi->xdi_TotalSectors = 80 * 22;
  164.   xdi->xdi_Cylinders    = 80;
  165.   xdi->xdi_CylSectors   = 22;
  166.   xdi->xdi_Heads        = 2;
  167.   xdi->xdi_TrackSectors = 11;
  168.   xdi->xdi_LowCyl       = 0;
  169.   xdi->xdi_HighCyl      = 79;
  170.  
  171.   /* read and skip header ID text */
  172.   READLONG(tfsize); SKIP(tfsize);
  173.  
  174.   /* read attached textfile (if it exists) */
  175.   READLONG(tfsize);
  176.   xdi->xdi_DataPos = ai->xai_InPos + tfsize;
  177.  
  178.   if (tfsize) {
  179.     ALLOCOBJ(struct xadTextInfo *, ti, XADOBJ_TEXTINFO, NULL);
  180.     xdi->xdi_TextInfo = ti;
  181.  
  182.     ALLOC(UBYTE *, textin, tfsize);
  183.     READ(textin, tfsize);
  184.     ti->xti_Size = EndGetM32(textin+tfsize-4);
  185.     ALLOC(STRPTR, ti->xti_Text, ti->xti_Size+1);
  186.     if ((err = ZAP_decrunch(textin, ti->xti_Text, tfsize))) goto exit_handler;
  187.     ti->xti_Text[ti->xti_Size] = '\0';
  188.   }
  189.     
  190. exit_handler:
  191.   if (textin) FREE(textin);
  192.  
  193.   if (err) {
  194.     if (!xdi) return err;
  195.     ai->xai_Flags |= XADAIF_FILECORRUPT;
  196.     ai->xai_LastError = err;
  197.   }
  198.   return XADERR_OK;
  199. }
  200.  
  201.  
  202.  
  203. #define ZAP_CYLSIZE   (22*512)    /* size of one cylinder */
  204. #define ZAP_BLOCKSIZE (22*512*8)  /* size of one block    */
  205.  
  206. struct ZAPstate {
  207.   UBYTE data[ZAP_BLOCKSIZE+260], temp[ZAP_BLOCKSIZE], block;
  208. };
  209.  
  210. ASM(LONG) ZAP_UnArchive(REG(a0, struct xadArchiveInfo *ai), XADBASE) {
  211.   struct ZAPstate *zs;
  212.   UBYTE buffer[4], cyl, block;
  213.   LONG err = XADERR_OK;
  214.   ULONG crlen;
  215.  
  216.   if (!(zs = (struct ZAPstate *) ai->xai_PrivateClient)) {
  217.     ALLOC(struct ZAPstate *, zs, sizeof(struct ZAPstate));
  218.     ai->xai_PrivateClient = (APTR) zs;
  219.     zs->block = 99; /* sentinel value */
  220.   }
  221.   
  222.   for (cyl = ai->xai_LowCyl; cyl <= ai->xai_HighCyl; cyl++) {
  223.     /* if the current block isn't the one needed... */
  224.     if ((block = cyl >> 3) != zs->block) {
  225.  
  226.       /* if it's not just the next block we need */
  227.       if (zs->block != (block-1)) {
  228.         /* go back to start of disk and skip forward to appropriate block */
  229.         int skip = block;
  230.         SEEK(ai->xai_CurDisk->xdi_DataPos);
  231.         while (skip--) { READLONG(crlen); SKIP(crlen); }
  232.       }
  233.  
  234.       /* read (possibly crunched) block into block buffer */
  235.       READLONG(crlen);
  236.       if (crlen > ZAP_BLOCKSIZE) ERROR(INPUT);
  237.       READ(zs->data, crlen);
  238.  
  239.       /* if the block is crunched */
  240.       if (crlen != ZAP_BLOCKSIZE) {
  241.         /* decrunch it to temp buffer */
  242.         if (EndGetM32(zs->data+crlen-4) > ZAP_BLOCKSIZE) ERROR(OUTPUT);
  243.         if ((err = ZAP_decrunch(zs->data, zs->temp, crlen))) goto exit_handler;
  244.  
  245.         /* un-RLE back to block buffer */
  246.         ZAP_rledecode(zs->temp, zs->data);
  247.       }
  248.       zs->block = block;
  249.     }
  250.  
  251.     WRITE(zs->data + ((cyl & 7) * ZAP_CYLSIZE), ZAP_CYLSIZE);
  252.   }
  253.  
  254. exit_handler:
  255.   return err;
  256. }
  257.  
  258. ASM(void) ZAP_Free(REG(a0, struct xadArchiveInfo *ai), XADBASE) {
  259.   if (ai->xai_PrivateClient) {
  260.     FREE(ai->xai_PrivateClient);
  261.     ai->xai_PrivateClient = NULL;
  262.   }
  263. }
  264.  
  265. const struct xadClient ZAP_Client = {
  266.   NEXTCLIENT, XADCLIENT_VERSION, 4, ZAP_VERSION, ZAP_REVISION,
  267.   40, XADCF_DISKARCHIVER|XADCF_FREEDISKINFO|XADCF_FREETEXTINFO,
  268.   0, "ZAP",
  269.   (BOOL (*)()) ZAP_RecogData,
  270.   (LONG (*)()) ZAP_GetInfo,
  271.   (LONG (*)()) ZAP_UnArchive,
  272.   (void (*)()) ZAP_Free
  273. };
  274.